
#pragma used+
sfrb TWBR=0;
sfrb TWSR=1;
sfrb TWAR=2;
sfrb TWDR=3;
sfrb ADCL=4;
sfrb ADCH=5;
sfrw ADCW=4;      
sfrb ADCSRA=6;
sfrb ADMUX=7;
sfrb ACSR=8;
sfrb UBRRL=9;
sfrb UCSRB=0xa;
sfrb UCSRA=0xb;
sfrb UDR=0xc;
sfrb SPCR=0xd;
sfrb SPSR=0xe;
sfrb SPDR=0xf;
sfrb PIND=0x10;
sfrb DDRD=0x11;
sfrb PORTD=0x12;
sfrb PINC=0x13;
sfrb DDRC=0x14;
sfrb PORTC=0x15;
sfrb PINB=0x16;
sfrb DDRB=0x17;
sfrb PORTB=0x18;
sfrb PINA=0x19;
sfrb DDRA=0x1a;
sfrb PORTA=0x1b;
sfrb EECR=0x1c;
sfrb EEDR=0x1d;
sfrb EEARL=0x1e;
sfrb EEARH=0x1f;
sfrw EEAR=0x1e;   
sfrb UBRRH=0x20;
sfrb UCSRC=0X20;
sfrb WDTCR=0x21;
sfrb ASSR=0x22;
sfrb OCR2=0x23;
sfrb TCNT2=0x24;
sfrb TCCR2=0x25;
sfrb ICR1L=0x26;
sfrb ICR1H=0x27;
sfrb OCR1BL=0x28;
sfrb OCR1BH=0x29;
sfrw OCR1B=0x28;  
sfrb OCR1AL=0x2a;
sfrb OCR1AH=0x2b;
sfrw OCR1A=0x2a;  
sfrb TCNT1L=0x2c;
sfrb TCNT1H=0x2d;
sfrw TCNT1=0x2c;  
sfrb TCCR1B=0x2e;
sfrb TCCR1A=0x2f;
sfrb SFIOR=0x30;
sfrb OSCCAL=0x31;
sfrb OCDR=0x31;
sfrb TCNT0=0x32;
sfrb TCCR0=0x33;
sfrb MCUCSR=0x34;
sfrb MCUCR=0x35;
sfrb TWCR=0x36;
sfrb SPMCR=0x37;
sfrb TIFR=0x38;
sfrb TIMSK=0x39;
sfrb GIFR=0x3a;
sfrb GICR=0x3b;
sfrb OCR0=0X3c;
sfrb SPL=0x3d;
sfrb SPH=0x3e;
sfrb SREG=0x3f;
#pragma used-

#asm
	#ifndef __SLEEP_DEFINED__
	#define __SLEEP_DEFINED__
	.EQU __se_bit=0x40
	.EQU __sm_mask=0xB0
	.EQU __sm_powerdown=0x20
	.EQU __sm_powersave=0x30
	.EQU __sm_standby=0xA0
	.EQU __sm_ext_standby=0xB0
	.EQU __sm_adc_noise_red=0x10
	.SET power_ctrl_reg=mcucr
	#endif
#endasm

#pragma used+

void delay_us(unsigned int n);
void delay_ms(unsigned int n);

#pragma used-

unsigned char set_wr=1;
eeprom unsigned char settings[128];

unsigned char lifes;
unsigned char ammo;
unsigned char clips;
unsigned char damage;

unsigned char shot_delay = 0;
unsigned char hit_delay = 0;

unsigned char sound_cursor = 0;
unsigned char sound_delay = 0;

bit hit_led_blink = 0;
unsigned char hit_led_blink_ct = 0;
unsigned char hit_led_show_delay = 0;

unsigned char reload_delay = 0;
bit reload_waitup = 0;
bit fire_waitup = 0;

bit display_blink = 0;
bit display_off = 0;
unsigned short display_off_ct = 0;
unsigned char display_blink_ct = 0;

bit respawn_enabled = 1;

const flash unsigned char display_symbols[] =
{
0b00101000, 
0b11101101, 
0b00110100, 
0b10100100, 
0b11100001, 
0b10100010, 
0b00100010, 
0b11101100, 
0b00100000, 
0b10100000, 
0b11111110, 
0b11111011, 
0b01111111, 
0b10111111, 
0b11101111, 
0b11111101, 
0b11110111, 
0b11011111, 
0b00111011, 
0b11111111, 
};

void display_init()
{
DDRC  = 0b11111111;
PORTC = 0b11111111;
}

void digit_show(unsigned char i)
{
if(!display_off)
PORTC = display_symbols[i];
}

void display_wakeup()
{
display_off = 0;
display_off_ct = 0;
}

void btn_init()
{

DDRA  = 0b00000000;
PORTA = 0b11111111;

DDRD.7 = 0;

}

unsigned char btn_a_pressed()
{
return (PINA.0 == 0);
}

unsigned char btn_b_pressed()
{
return (PINA.1 == 0);
}

unsigned char btn_c_pressed()
{
return (PINA.2 == 0);
}

unsigned char recv_buffer[3] = {0,0,0};

flash const unsigned char sounds[] =
{

10, 3, 1,
0,

150, 2, 1,
0,

2, 0x04, 30,
2, 0x04, 10,
0,

3, 0x10, 1,
0,

3, 8, 1,
3, 0x10, 1,
0,

3, 0x10, 1,
3, 8, 1,
0,

25, 3, 1,
25, 2, 1,
25, 3, 1,
25, 2, 1,
25, 3, 1,
25, 2, 1,
25, 3, 1,
25, 2, 1,
25, 3, 1,
25, 2, 1,
0,

2, 0x3, 0,
2, 0x3, 5,
2, 0x3, 10,
2, 0x3, 15,
0,
};

void sound_off()
{

TCCR1A = TCCR1B = 0;
DDRD.5 = 0;
PORTD.5 = 0; 

return;
}

void sound_init()
{
sound_off();
}

void sound_update()
{
if(sound_delay == 0) 
return;

if(--sound_delay > 0) 
return;

sound_delay = sounds[sound_cursor++];
if(!sound_delay)
{
sound_off();
return;
}

TCCR1A = 0x40;
TCCR1B = 0x0A;
OCR1AH = sounds[sound_cursor++];
OCR1AL = sounds[sound_cursor++];
if(TCNT1L > OCR1AL)
TCNT1L = 0;
if(TCNT1H > OCR1AH)
TCNT1H = 0;

DDRD.5 = 1;
}

void sound_play(unsigned char id)
{

sound_cursor = 0;
while(id)
{
if(sounds[sound_cursor] == 0)
id--;
sound_cursor++;
}

sound_delay = 1;
sound_update();
}

void sensor_init()
{

DDRD.4  = 1;
PORTD.4 = 1;

DDRD.3  = 0;
PORTD.3 = 1;
}

void init_clock()
{

TCCR0 = 0x0D;
TCNT0 = 0x00;
OCR0  = 0xff;

TIMSK = 0x01; 
}

void sensor_led(unsigned char on)
{
PORTD.4 = !on;
}

void signal_send()
{
unsigned char c,i;

#asm("cli")

ASSR=0x00;
TCCR2=0x19;
TCNT2=0x00;
OCR2=0xA6; 

DDRD.7 = 1; delay_us(2400); DDRD.7 = 0;

for(i=0;i<3;i++)
for(c=0;c<8;c++)
{
delay_us(600);
DDRD.7 = 1;
if(recv_buffer[i] & 1)
delay_us(1200);
else
delay_us(600);
DDRD.7=0;
recv_buffer[i] >>= 1;
}

#asm("sei")
}

unsigned char crc8(unsigned char data, unsigned char crc)
{
unsigned char i;

crc ^= data;
for (i = 0; i < 8; i++)
crc = crc & 0x80 ? (crc << 1) ^ 0x31 : crc << 1;

return crc;
}

unsigned char signal_recv()
{
unsigned char bits = 0;
unsigned char bytes = 0;
unsigned char bcount = 0;

recv_buffer[0] = recv_buffer[1] = recv_buffer[2] = 0;

if(PIND.3 != 0)
return 0;

#asm("cli")

ASSR=0x00;
TCCR2=0x06;
TCNT2=0x00;
OCR2=0x00;

while(PIND.3 == 0)
if(TCNT2 >= 128)
{
#asm("sei")
return 0;
}

for(bytes=0; bytes<3; bytes++)
{
for(bits=0; bits<8; bits++)
{
unsigned char time = 0;

TCNT2 = 0;

while(PIND.3 == 1)
if(TCNT2 >= 128)
break;

time = TCNT2; 
time += (TCNT2/2);  

TCNT2=0;

while(PIND.3 == 0) 
if(TCNT2 >= 128)
break;

if(TCNT2 >= time) 
recv_buffer[bytes] |= (1 << bits);

bcount++;
}

if(TCNT2 >= 128)
break;
}

#asm("sei")
return bcount;
}

void init()
{

PORTA=0x00;
DDRA=0x00;

PORTB=0x00;
DDRB=0x00;

PORTD=0x00;
DDRD=0x00;

TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

MCUCR=0x00;
MCUCSR=0x00;

TIMSK=0x00;

ACSR=0x80;
SFIOR=0x00;
}

void game_respawn()
{
if(!respawn_enabled)
return;

lifes = 4;
ammo = 30;
clips = 4;
damage = 2;

sound_play(0);
display_wakeup();
digit_show(lifes);
respawn_enabled = 0;
}

void game_fire()
{
respawn_enabled = 1;

if(!ammo)
{
sound_play(3);
}
else
{
recv_buffer[0] = 0b11000000 | (damage & 0b00001111); 
recv_buffer[1] = 0b00000000; 
recv_buffer[2] = crc8(recv_buffer[1], crc8(recv_buffer[0], 0xff));
sound_off();
digit_show(19);
signal_send();
ammo--;
sound_play(7);
display_wakeup();
digit_show(lifes);

}
shot_delay = 10;

}

void game_die()
{
display_wakeup();
digit_show(16);

sound_play(6);

hit_led_show_delay = 250;
hit_delay = 250;
shot_delay = 250;
hit_led_blink = 1;
}

void game_hit(unsigned char dmg)
{
respawn_enabled = 1;

if(dmg > lifes)
lifes = 0;
else
lifes -= dmg;

display_wakeup();
digit_show(lifes); 

hit_led_blink = 0;
hit_led_show_delay = 150;
hit_delay = 100;
shot_delay = 150;

if(lifes == 0)
game_die();
else
sound_play(1);
}

void game_reload()
{
respawn_enabled = 1;

if(!clips)
return;

display_wakeup();
sound_play(5);

shot_delay = 150; 
reload_delay = 150;
reload_waitup = 1;
display_blink = 1;
}

void game_reloaded()
{
display_blink = 0;
display_wakeup();
digit_show(lifes);
sound_play(4);
clips--;
ammo = 30;
}

void game_miss()
{
sound_play(2);
}

unsigned char process_signal()
{
unsigned char u = signal_recv();
if(u==0)
return 1; 

if(u != 24)
return 1; 

if(recv_buffer[2] != crc8(recv_buffer[1], crc8(recv_buffer[0], 0xff))) 
{
return 1;
}

if(recv_buffer[0] == 0x81 )
{
game_respawn();
return 1;
}

if(recv_buffer[0] == 0xC2 )
{
if(lifes)

game_hit(1);

return 1;
}

return 0;
}

interrupt [10] void timer0_ovf_isr(void)
{
sound_update();

if(shot_delay)
shot_delay--;

if(hit_delay)
hit_delay--;

if(reload_delay)
reload_delay--;

if(reload_delay == 1)
game_reloaded();

if(display_blink)
{
if(display_blink_ct == 10)
digit_show(19);

if(display_blink_ct == 20)
digit_show(lifes);

display_blink_ct++;

if(display_blink_ct > 20)
display_blink_ct = 0;
}

if(hit_led_show_delay)
{
hit_led_show_delay--;

if(hit_led_show_delay == 0)
sensor_led(0);
else
{
if(hit_led_blink)
{
sensor_led(hit_led_blink_ct <= 25);
hit_led_blink_ct++;
if(hit_led_blink_ct > 50)
hit_led_blink_ct = 0;
}
else
sensor_led(1);
}
}

if(!lifes) 
{
if(display_blink_ct % 5 == 0)
digit_show(10+(display_blink_ct/5));

display_blink_ct++;

if(display_blink_ct >= 6*5)
display_blink_ct = 0;
}

if(display_off_ct > 800)
{
digit_show(19);
display_off = 1;
}
else
display_off_ct++;
}

void key_respawn_fire()
{
recv_buffer[0] = 0b10000001; 
recv_buffer[1] = 0b00000000; 
recv_buffer[2] = crc8(recv_buffer[1], crc8(recv_buffer[0], 0xff));
signal_send();
shot_delay = 6;
}

void key_main()
{
digit_show(16);
lifes = 1; 

#asm("sei")

while(1)
{
if(shot_delay == 0)
{
if(btn_b_pressed())
key_respawn_fire();
}
}
}

void gun_main()
{
digit_show(1);

#asm("sei")

while(1)
{
while(!lifes)
{
if(!process_signal())
game_miss();
}

game_respawn();

while(lifes)
{
if(!hit_delay)
if(!process_signal())
game_miss();

if(shot_delay == 0)
{
if(btn_b_pressed())
game_fire();

if(!reload_waitup)
{
if(btn_c_pressed())
game_reload();
}
else 
{
if(btn_c_pressed())
reload_waitup = 0;
}
}
}
}
}

void main()
{
init();
btn_init();
display_init();
sound_init();
sensor_init();

init_clock();

sound_play(0);

if(settings[0] == 1) 
key_main();
else
gun_main();
}
